package com.xishu.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.krysalis.barcode4j.impl.code39.Code39Bean;
import org.krysalis.barcode4j.output.bitmap.BitmapCanvasProvider;
import org.krysalis.barcode4j.tools.UnitConv;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class ImgService implements Tools {
    private static Logger logger = LoggerFactory.getLogger(ImgService.class);

    private static ImgService instance = new ImgService();

    private ImgService() {
    }

    public static ImgService getInstance() {
        return instance;
    }


    private static final int BLACK = 0xFF000000;

    private static final int WHITE = 0xFFFFFFFF;

    /**
     * 生成文件
     *
     * @param matrix
     * @param format
     * @param file
     * @throws IOException
     */
    public void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, file)) {
            throw new IOException("Could not write an image of format " + format + " to " + file);
        }
    }

    /**
     * 生成图片缓存
     *
     * @param matrix
     * @return
     */
    private BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }

    /**
     * 产生二维码文件图片
     *
     * @param url
     * @return
     */
    public File createQrCode(String url) {
        try {
            Map<EncodeHintType, String> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 400, 400, hints);
            File file = MongoId.getInstance().generateTmpFile("jpg");

            if (file.exists() || ((file.getParentFile().exists() || file.getParentFile().mkdirs()) && file.createNewFile())) {
                writeToFile(bitMatrix, "jpg", file);
                logger.info("generate weixin pay file {}", file.getAbsolutePath());
            }

            return file;

        } catch (Exception e) {
            logger.error("e", e);
        }

        return null;
    }

    /**
     * 生成中间有logo的二维码
     *
     * @param url
     * @param logoFile 用来存放带有logo的二维码图片
     */
    public File createLogoQrCode(String url, File logoFile) {
        int width = 300;
        int height = 300;
        // 1、设置二维码的一些参数
        HashMap hints = new HashMap();

        // 1.1设置字符集
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");

        // 1.2设置容错等级；因为有了容错，在一定范围内可以把二维码p成你喜欢的样式
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

        // 1.3设置外边距;(即白色区域)
        hints.put(EncodeHintType.MARGIN, 1);

        // 2、生成二维码
        try {
            // 2.1定义BitMatrix对象
            BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, width, height, hints);

            // 2.2、设置二维码存放路径,以及二维码的名字

            // qrFile用来存放生成的二维码图片
            File qrFile = MongoId.getInstance().generateTmpFile("jpg");

            // 2.3、执行生成二维码
            MatrixToImageWriter.writeToPath(bitMatrix, "jpg", qrFile.toPath());

            if (logoFile == null || !logoFile.exists()) {
                return qrFile;
            }

            // 2.4在二维码中添加logo
            LogoConfig logoConfig = new LogoConfig();
            return addLogo(qrFile, logoFile, logoConfig);
        } catch (Exception e) {
            logger.error("e", e);
            return null;
        }
    }


    /**
     * @param qrPic      二维码文件路径
     * @param logoPic    logo文件路径
     * @param logoConfig 配置类
     */
    private static File addLogo(File qrPic, File logoPic, LogoConfig logoConfig) {

        if (!qrPic.isFile() || !logoPic.isFile()) {
            logger.info("file not found!");
            return null;
        }

        try {
            // 1、读取二维码图片，并构建绘图对象
            BufferedImage image = ImageIO.read(qrPic);
            Graphics2D graph = image.createGraphics();

            // 2、读取logo图片
            BufferedImage logo = ImageIO.read(logoPic);

            int widthLogo = image.getWidth() / logoConfig.getLogoPart();
            int heightLogo = image.getHeight() / logoConfig.getLogoPart();

            // 3、计算图片放置的位置
            int x = (image.getWidth() - widthLogo) / 2;
            int y = (image.getHeight() - heightLogo) / 2;

            // 4、绘制图片
            graph.drawImage(logo, x, y, widthLogo, heightLogo, null);
            graph.drawRoundRect(x, y, widthLogo, heightLogo, 10, 10);
            graph.setStroke(new BasicStroke(logoConfig.getBorder()));
            graph.setColor(logoConfig.getBorderColor());
            graph.drawRect(x, y, widthLogo, heightLogo);

            graph.dispose();
            File tmpFile = MongoId.getInstance().generateTmpFile("jpg");
            ImageIO.write(image, "jpeg", tmpFile);

            return tmpFile;
        } catch (Exception e) {
            logger.error("e", e);
            return null;
        }
    }

    /**
     * 生成条形码
     * 宽176
     * 高105
     *
     * @param barCode
     * @return
     */
    public File createBarCode(String barCode) throws Exception {
        if (isEmpty(barCode)) {
            logger.info("bar code is empty");
            return null;
        }

        File tmpFile = MongoId.getInstance().generateTmpFile("jpg");

        Code39Bean bean = new Code39Bean();

        // 精细度
        final int dpi = 150;

        // module宽度
        final double moduleWidth = UnitConv.in2mm(1.0f / dpi);

        // 配置对象
        bean.setModuleWidth(moduleWidth);
        bean.setWideFactor(3);
        bean.doQuietZone(false);

        String format = "image/png";
        FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
        try {

            // 输出到流
            BitmapCanvasProvider canvas = new BitmapCanvasProvider(fileOutputStream, format, dpi,
                    BufferedImage.TYPE_BYTE_BINARY, false, 0);

            // 生成条形码
            bean.generateBarcode(canvas, barCode);

            // 结束绘制
            canvas.finish();

            return tmpFile;
        } finally {
            IOUtils.closeQuietly(fileOutputStream);
        }
    }

    public static void main(String[] args) throws Exception {
//        File barCode = ImgService.getInstance().createBarCode("123456789");
//        System.out.println("barCode.getAbsolutePath() = " + barCode.getAbsolutePath());
//        File logoQrCode = createLogoQrCode(300, 300, "http://www.baidu.com", new File("D:\\项目\\dola\\logo.100x100.png"));
//        File logoQrCode = createLogoQrCode(300, 300, "http://www.baidu.com", null);
//        System.out.println("logoQrCode = " + logoQrCode);
    }
}
